"
Specific version of compiled code for blocks.

In addition the execution mechanics, a compiled block has an extra literal: the last literal is the compiled code of the outer method or block (see #outerCode)



"
Class {
	#name : 'CompiledBlock',
	#superclass : 'CompiledCode',
	#type : 'compiledMethod',
	#category : 'Kernel-CodeModel-Methods',
	#package : 'Kernel-CodeModel',
	#tag : 'Methods'
}

{ #category : 'constants' }
CompiledBlock class >> trailerSize [
	^ 0
]

{ #category : 'displaying' }
CompiledBlock >> displayStringOn: stream [

	self printOn: stream
]

{ #category : 'accessing' }
CompiledBlock >> endPC [
	"Answer the index of the last bytecode"
	^ self size
]

{ #category : 'testing' }
CompiledBlock >> hasMethodReturn [
	"Answer whether the receiver has a method-return ('^') in its code."
	^ (InstructionStream on: self) scanFor: [:byte |
		 self encoderClass methodReturnBytecodes includes: byte]
]

{ #category : 'testing' }
CompiledBlock >> hasPragmaNamed: aSymbol [
	<reflection: 'Class structural inspection - Pragma'>
	^ false
]

{ #category : 'testing' }
CompiledBlock >> hasProperties [
	^false
]

{ #category : 'accessing - pragmas & properties' }
CompiledBlock >> hasProperty: aString [

	^ false
]

{ #category : 'testing' }
CompiledBlock >> hasSourceCode [
	^ self method hasSourceCode
]

{ #category : 'comparing' }
CompiledBlock >> hash [
	"CompiledMethod>>#= compares code, i.e. same literals and same bytecode.
	 So we look at the header, methodClass and some bytes between initialPC and endPC,
	 but /not/ the selector because the equal method does not compare selectors.
	 Note that we must override ByteArray>hash which looks at all bytes of the receiver.
	 Using bytes from the pointer part of a COmpiledmethod can lead to a variable hash
	 if and when when the GC moves literals in the receiver."
	| initialPC endPC hash |
	initialPC := self initialPC.
	endPC := self endPC.
	hash := self species hash + self header + initialPC + endPC.
	"sample approximately 20 bytes"
	initialPC to: endPC by: (endPC - initialPC // 20 max: 1) do:
		[:i| hash := hash + (self at: i)].
	^hash

	"(CompiledMethod>>#hash) hash"
]

{ #category : 'accessing' }
CompiledBlock >> indexInOuter [

	| index |
	index := self outerCode literals indexOf: self.
	index > 0 ifTrue: [ ^ index ].

	"If not found, look for clean blocks with myself as their code"
	^ self outerCode literals detectIndex: [ :lit |
		  lit isBlock and: [ lit compiledBlock == self ] ]
]

{ #category : 'accessing' }
CompiledBlock >> indexesInOuter [

	| index |
	index := self outerCode literals indexOf: self.
	index > 0 ifTrue: [ ^ ByteArray with: index ].

	"If not found, look for clean blocks with myself as their code.
	Use a final zero marker to indicate this is a clean block"
	index := self outerCode literals detectIndex: [ :lit |
		         lit isBlock and: [ lit compiledBlock == self ] ].
	^ ByteArray with: index with: 0
]

{ #category : 'testing' }
CompiledBlock >> isCompiledBlock [
	^ true
]

{ #category : 'testing' }
CompiledBlock >> isEmbeddedBlock [
	^ true
]

{ #category : 'testing' }
CompiledBlock >> isInstalled [

	^ self method isInstalled
]

{ #category : 'testing' }
CompiledBlock >> isTestMethod [
	^ false
]

{ #category : 'comparing' }
CompiledBlock >> literalEqual: other [
	"Two compiled blocks should be unified in the literal frame only if they are the same block.
	If they are two different blocks with the same code, do not unify them: we want to have both in the literal array"

	^ self == other
]

{ #category : 'accessing - literals' }
CompiledBlock >> literalsToSkip [

	^ 1
]

{ #category : 'accessing' }
CompiledBlock >> method [
	"answer the compiled method that I am installed in, or nil if none."
	^self outerCode method
]

{ #category : 'accessing' }
CompiledBlock >> methodClass [
	"answer the compiled method that I am installed in, or nil if none."
	^self outerCode methodClass
]

{ #category : 'accessing' }
CompiledBlock >> outerCode [
	"answer the compiled code that I am installed in, or nil if none."
	^self literalAt: self numLiterals
]

{ #category : 'accessing' }
CompiledBlock >> outerCode: aCompiledCode [
	^self literalAt: self numLiterals put: aCompiledCode
]

{ #category : 'accessing' }
CompiledBlock >> pathOfLiteralIndexes [
	
	"Return the path of this compiled block inside the method literal frame.
	The path is a list of indexes.
	The user must interpret this list as a tree path, where nodes are methods/blocks and edges are literal indexes.
	
	This is useful among other things to serialize a symbolic version of this block"
	^ self outerCode pathOfLiteralIndexes copyWithAll: self indexesInOuter
]

{ #category : 'accessing - pragmas & properties' }
CompiledBlock >> pragmas [
	<reflection: 'Class structural inspection - Pragma'>
	^ #()
]

{ #category : 'printing' }
CompiledBlock >> printOn: anStream [

	anStream
		nextPutAll: 'a CompiledBlock: ';
		nextPutAll: self sourceNode sourceCode
]

{ #category : 'compatibility' }
CompiledBlock >> properties [
	^ nil->nil
]

{ #category : 'accessing - pragmas & properties' }
CompiledBlock >> propertyAt: aString [

	^ nil
]

{ #category : 'comparing' }
CompiledBlock >> sameLiteralsAs: method [
	"Compare my literals to those of method. This is needed to compare compiled methods."

	| numLits literal1 literal2 |
	(numLits := self numLiterals) ~= method numLiterals
		ifTrue: [ ^ false ].
	"The last literal requires special checking instead of using #literalEqual:"
	1 to: numLits - 1 do: [ :index |
		literal1 := self literalAt: index.
		literal2 := method literalAt: index.
		(literal1 == literal2 or: [ literal1 literalEqual: literal2 ])
			ifFalse: [ ^ false ] ].
	"we can't do = on outer code or it will recursively call this code"
	^ true
]

{ #category : 'accessing' }
CompiledBlock >> selector [

	<reflection: 'Class structural inspection - Selectors and methods inspection'>
	^ self outerCode selector
]

{ #category : 'source code management' }
CompiledBlock >> sourceCode [
	^ self outerCode sourceCode
]

{ #category : 'source code management' }
CompiledBlock >> sourcePointer [
	^self outerCode sourcePointer
]

{ #category : 'debugger support' }
CompiledBlock >> stepIntoQuickMethods [
	^self method stepIntoQuickMethods
]

{ #category : 'debugger support' }
CompiledBlock >> stepIntoQuickMethods: aBoolean [
	^self method stepIntoQuickMethods: aBoolean
]
